#pragma once
#include "XThread.h"
#include "RoboServer.h"
#include "H264Captor.h"

#define SERVER_PORT							9999
#define SERVER_RTP_PORT				55552
#define SERVER_RTCP_PORT				55553
#define BUF_MAX_SIZE							(1024*1024)

#define H264_FILE_NAME   "test.h264"

#define RTP_VESION								2

#define RTP_PAYLOAD_TYPE_H264   96
#define RTP_PAYLOAD_TYPE_AAC    97

#define RTP_HEADER_SIZE					12
#define RTP_MAX_PKT_SIZE				1400

/*
 *
 *	0								1									2									3
 *	7	6	5	4	3	2	1	0	|	7	6	5	4	3	2	1	0	|	7	6	5	4	3	2	1	0	|	7	6	5	4	3	2	1	0
 *	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *	|	V	|P|X|		CC		|M|			PT				|						sequence number					|
 *	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *	|																timestamp															|
 *	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *	|										synchronization source (SSRC) identifier									|
 *	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *	|										contributing source (CSRC) identifiers										|
 *	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *																	......
 *	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */

class RtspServer : public RoboServer, public XThread
{
public:
    RtspServer();
    ~RtspServer();

    void Main() override;


public:
    int handleCmd_OPTIONS(char* result, int cseq);
    int handleCmd_DESCRIBE(char* result, int cseq, char* url);
    int handleCmd_SETUP(char* result, int cseq, int clientRtpPort);
    int handleCmd_PLAY(char* result, int cseq);
    int handleCmd_TEARDOWN(char* result, int cseq);

    void doClient(int clientSockfd, const char* clientIP, int clientPort,
        int serverRtpSockfd, int serverRtcpSockfd);

    void playLive(const char* clientIP, int clientRtpPort, H264Captor& h264Captor, int serverRtpSockfd);

public:
    struct RtpHeader
    {
        /* byte 0 */
        uint8_t csrcLen : 4;
        uint8_t extension : 1;
        uint8_t padding : 1;
        uint8_t version : 2;

        /* byte 1 */
        uint8_t payloadType : 7;
        uint8_t marker : 1;

        /* bytes 2,3 */
        uint16_t seq;

        /* bytes 4-7 */
        uint32_t timestamp;

        /* bytes 8-11 */
        uint32_t ssrc;
    };

    struct RtpPacket
    {
        struct RtpHeader rtpHeader;
        uint8_t payload[0];
    };

    void rtpHeaderInit(struct RtpPacket* rtpPacket, uint8_t csrcLen, uint8_t extension,
        uint8_t padding, uint8_t version, uint8_t payloadType, uint8_t marker,
        uint16_t seq, uint32_t timestamp, uint32_t ssrc);
    int rtpSendPacket(int socket, const char* ip, int16_t port, struct RtpPacket* rtpPacket, uint32_t dataSize);

public:
    inline int startCode3(char* buf);
    inline int startCode4(char* buf);
    char* findNextStartCode(char* buf, int len);
    int getFrameFromH264File(int fd, char* frame, int size);
    int rtpSendH264Frame(int socket, const char* ip, int16_t port,
        struct RtpPacket* rtpPacket, uint8_t* frame, uint32_t frameSize);
    int captureFrameFromCam(char* frame, H264Captor* h264captor);

private:
    std::thread liveTh;
    bool isPlay = false;
    bool haveNotPlay = true;
};

